#include "cheeseBoard.h"

CheeseBoard::CheeseBoard(QObject *parent, int cheeseBoardWidth, int cheeseBoardHeight): QGraphicsScene(parent)
{
   this->cheeseBoardWidth = cheeseBoardWidth;
   this->cheeseBoardHeight = cheeseBoardHeight;
   //init record location's table
   for(int i = 0; i < row; i++)
       for(int j = 0; j < column; j++)
          recoLocTable[i][j] = 0;  //0-none,1-has cheese
   //init cheeses
   initCheese();
}

QRectF CheeseBoard::boundingRect() const
{
    return QRectF(0, 0, cheeseBoardWidth, cheeseBoardHeight);
}

QGraphicsView* CheeseBoard::toGetViewPort()
{
    QGraphicsView* view = NULL;
    view = views().first();
    return view;
}

MainWindows* CheeseBoard::toGetParent()
{
    MainWindows* mainWindow = NULL;
    mainWindow  =  qobject_cast<MainWindows *>(parent());
    return mainWindow;
}

void CheeseBoard::startNewGame()
{
  QList<QGraphicsItem *> itemsList = items();
  QGraphicsItem* graphicsItem = NULL;

  if(itemsList.size()!=0)
  {
      //clear items in cheeseboard
      for(int i=0; i<itemsList.size();i++)
      {
         graphicsItem = itemsList.at(i);
         removeItem(graphicsItem);
         delete graphicsItem;
         graphicsItem = NULL;
      }//end for
  }//end if

  //init cheeses
  initCheese();
}

void CheeseBoard::initCheese()
{
    double x_anx = 5.0; //original points
    double y_anx=  5.0; //original points
    double radius = 28.0; //fixed value?
    double moveX = (cheeseBoardWidth-2.5*radius +x_anx)/(column-1);
    double moveY = (cheeseBoardHeight-2.5*radius + y_anx)/(row-1);
    QString name = "";

  for (int i = 0; i < row; i++) {
     for(int j = 0; j<column; j++){
         if (types[i][j]!=emask)
         {
            if(i<row/2)
            {
                Cheese* cheese = new Cheese(QColor(0,0,0),types[i][j],radius,QPoint(i,j));
                cheese->setPos(QPointF(x_anx,y_anx));
                addItem(cheese);
                recoLocTable[i][j] = 1;
                name.clear();
            }
            if(i>row/2)
            {
                Cheese* cheese = new Cheese(QColor(255,0,0),types[i][j],radius,QPoint(i,j));
                cheese->setPos(QPointF(x_anx,y_anx));
                addItem(cheese);
                recoLocTable[i][j] = 1;
                name.clear();
            }
         }//end if
         else
         {
            Masks* masks = new Masks(types[i][j],radius,QPoint(i,j));
            masks->setPos(QPointF(x_anx,y_anx));
            addItem(masks);
            masks->setOpacity(0.1);
        }

        points.append(QPointF(x_anx,y_anx));// saved QPoints for each ponts in cheeseboard

        x_anx = x_anx + moveX;
    }
    x_anx = 5.0;
    y_anx = y_anx + moveY;
  }//end for
}

/*
 @param-Cheese: a cheese which is ready to move
 @param:-Masks: a point where cheese to move
 */
 bool CheeseBoard::isLegalMove(const Cheese& from,const Masks& to)
 {
   bool isLegal = false;
   isLegal = cheeseRule(from,to); //all avaiable points to move
   return isLegal;
 }
 /*
  @param-Cheese: a cheese which is ready to eat
  @param:-Masks: a cheese which to be ate
  */
  bool CheeseBoard::isLegalEat(const Cheese& from,const Cheese& to)
  {
    qDebug()<<"In isLegalEat";
    bool isLegal = false;
    int count =0;
    Masks* mask = new Masks(emask,to.toGetRadius(),to.toGetLocation());
    isLegal = cheeseRule(from,*mask);
    delete mask; //delete temp. variable

    if(!isLegal) //different eating rule
    {
      if( from.toGetCheesesType() == eche) //eche
      {
         if(   from.toGetLocation().x() == to.toGetLocation().x()
            || from.toGetLocation().y() == to.toGetLocation().y())
             isLegal = true;
      }
      if( from.toGetCheesesType() == epao)  //epao
      {
          if(    from.toGetLocation().x() > to.toGetLocation().x()
              && from.toGetLocation().y() == to.toGetLocation().y()) //up
          {
              for(int i=to.toGetLocation().x(); i<from.toGetLocation().x(); i++){
               if (recoLocTable[i][from.toGetLocation().y()] == 1)
                   count++;
              }//end for
              if(count==2)
                isLegal = true;
              else
                isLegal = false;
          }
         else if(    from.toGetLocation().x() < to.toGetLocation().x()
              && from.toGetLocation().y() == to.toGetLocation().y()) //down
          {
              for(int i=from.toGetLocation().x(); i<to.toGetLocation().x(); i++){
               if (recoLocTable[i][from.toGetLocation().y()] == 1)
                   count++;
              }//end for
              if(count==2)
                isLegal = true;
              else
                isLegal = false;
          }
          else if(    from.toGetLocation().x() == to.toGetLocation().x()
              && from.toGetLocation().y() > to.toGetLocation().y()) //left
          {
              for(int i=to.toGetLocation().y(); i<from.toGetLocation().y(); i++){
               if (recoLocTable[from.toGetLocation().x()][i] == 1)
                   count++;
              }//end for
              if(count==2)
                isLegal = true;
              else
                isLegal = false;
          }
          else if(    from.toGetLocation().x() == to.toGetLocation().x()
              && from.toGetLocation().y() < to.toGetLocation().y()) //right
          {
              for(int i=from.toGetLocation().y(); i<to.toGetLocation().y(); i++){
               if (recoLocTable[from.toGetLocation().x()][i] == 1)
                   count++;
              }//end for
              if(count==2)
                isLegal = true;
              else
                isLegal = false;
          }
          else{}
      }//end if 'epao'

//      if( from.toGetCheesesType() == ejiang)
//      {

//      }
//      if( from.toGetCheesesType() == eshuai)
//      {

//      }
     }//ene if

    //don't eat self-cheeses
    if ( QString::compare(from.toGetColor().name(),to.toGetColor().name(),Qt::CaseInsensitive)==0)
        isLegal = false;
    return isLegal;
  }

 /*
  */
 void CheeseBoard::reset()
 {
     cheese=NULL;
     mask=NULL;
     item=NULL;
 }

 void CheeseBoard::undoAction()
 {
//     Reciever* rev = new Reciever();
//     Command* cmd = new MoveCheeseCommand(rev);
//     Invoker* inv = new Invoker(cmd);
//     inv->Invoke();
 }


 void CheeseBoard::redoAction()
 {

 }

bool CheeseBoard::cheeseRule(const Cheese& cheese,const Masks& mask)
 {
    QPoint from = cheese.toGetLocation();
    QPoint to = mask.toGetLocation();
    bool isOK = false;
    qDebug()<<"from:"<<from;
    qDebug()<<"to:"<<to;

    switch(cheese.toGetCheesesType())
    {
     case emask:
     break;

    case eshuai:
     {
         if(
            ((to.x()== 7 && to.y() == 3)
            ||(to.x()== 7 && to.y() == 4)
            ||(to.x()== 7 && to.y() == 5)
            ||(to.x()== 9 && to.y() == 3)
            ||(to.x()== 9 && to.y() == 4)
            ||(to.x()== 9 && to.y() == 5)
            ||(to.x()== 8 && to.y() == 3)
            ||(to.x()== 8 && to.y() == 4)
            ||(to.x()== 8 && to.y() == 5)
            )
            && ( from.x()==to.x()|| from.y()==to.y())
            && ( from.x()-to.x() != 2 && from.x()-to.x() != -2)
            && ( from.y()-to.y() != 2 && from.y()-to.y() != -2)
            )
            isOK=true;
     }

     break;

    case eshi:
     {
       if(
          ((to.x()== 7 && to.y() == 3)
          ||(to.x()== 7 && to.y() == 5)
          || (to.x()== 9 && to.y() == 3)
          ||(to.x()== 9 && to.y() == 5)
          ||(to.x()== 8 && to.y() == 4))
          && ( from.x()-to.x() == 1 || from.x()-to.x() == -1)
          && ( from.y()-to.y() == 1 || from.y()-to.y() == -1)
          )
          isOK=true;
     }
    break;
    case ema:
    {
        if((to.y() - from.y() == - 2 || from.y() - to.y() ==  2)
            &&( to.x() - from.x() == -1 || to.x() - from.x() ==  1) ) //left
        {
            if( recoLocTable[from.x()][from.y()-1]==1 )
             isOK = false;
            else
             isOK = true;
        }
        else if ((from.x() - to.x() ==  1 || from.x() - to.x() == - 1)
            && (to.y() - from.y() ==  2 || from.y() - to.y() ==  -2)) //right
        {
            if( recoLocTable[from.x()][from.y()+1]==1 )
             isOK = false;
            else
             isOK = true;
        }

        else if( ( to.y() - from.y() == 1 || to.y() - from.y() ==  - 1)
            && (from.x() - to.x() == 2 || to.x() - from.x() ==  -2) )//up
        {
           if( recoLocTable[from.x()-1][from.y()]==1 )
            isOK = false;
           else
            isOK = true;
        }

        else if( (from.x() - to.x() == - 2 || to.x() - from.x() ==  2)
            &&( to.y() - from.y() == -1 || to.y() - from.y() ==  1) )//down
        {
           if( recoLocTable[from.x()+1][from.y()]==1 )
            isOK = false;
           else
            isOK = true;
        }
        else
         isOK = false;
    }
    break;

    case epao:
    case eche:
    {
     int diff_col = from.x()-to.x();
     int diff_row = from.y()-to.y();
     if( diff_col >0 && ( from.x()==to.x()|| from.y()==to.y()) ) //up
     {
         for(int i=to.x(); i<from.x();i++)
         {
           if(recoLocTable[i][from.y()] == 1)
             {
               isOK = false;
               break;
             }
           else
               isOK=true;
         }
     }
     else if ( diff_col <0 && ( from.x()==to.x()|| from.y()==to.y()) ) //down
     {
        for(int i=to.x(); i>from.x();i--)
        {
           if(recoLocTable[i][from.y()] == 1)
             {
               isOK = false;
               break;
             }
           else
               isOK=true;
         }
     }
     else{}

     if ( diff_row >0 && ( from.x()==to.x()|| from.y()==to.y())) //left
     {
         for(int i=to.y(); i<from.y();i++)
         {
           if(recoLocTable[from.x()][i] == 1)
             {
               isOK = false;
               break;
             }
           else
               isOK=true;
         }
     }
     else if ( diff_row <0 && ( from.x()==to.x()|| from.y()==to.y())) //right
     {
         for(int i=to.y(); i>from.y();i--)
         {
            if(recoLocTable[from.x()][i] == 1)
              {
                isOK = false;
                break;
              }
            else
                isOK=true;
          }
     }
     else{}
    }//end case 'eche'
    break;

    case ebing:
    {
     //!over river
     if( to.y()== from.y() && to.x()- from.x() == -1 && to.x()>4) //
         isOK = true;
     //over river
     else if (
              (from.x()==to.x()||from.y()==to.y())
              && to.x()<=4
              && (
                  ( from.x()-to.x() == 1 && from.x()-to.x() != -1 )
                  ||( from.y()-to.y() == 1 || from.y()-to.y() == -1)
                  )
              )
         isOK = true;
     else{}
    }
    break;

    case ejiang:
    {
        if(
           ((to.x()== 0 && to.y() == 3)
           ||(to.x()== 0 && to.y() == 4)
           ||(to.x()== 0 && to.y() == 5)
           ||(to.x()== 1 && to.y() == 3)
           ||(to.x()== 1 && to.y() == 4)
           ||(to.x()== 1 && to.y() == 5)
           ||(to.x()== 2 && to.y() == 3)
           ||(to.x()== 2 && to.y() == 4)
           ||(to.x()== 2 && to.y() == 5)
           )
           && ( from.x()==to.x()|| from.y()==to.y())
           && ( from.x()-to.x() != 2 && from.x()-to.x() != -2)
           && ( from.y()-to.y() != 2 && from.y()-to.y() != -2)
           )
           isOK=true;
    }
    break;
    case eshii:
    {
        if(((to.x()== 0 && to.y() == 3)
           ||(to.x()== 0 && to.y() == 5)
           || (to.x()== 1 && to.y() == 4)
           ||(to.x()== 2 && to.y() == 3)
           ||(to.x()== 2 && to.y() == 5))
           && ( from.x()-to.x() == 1 || from.x()-to.x() == -1)
           && ( from.y()-to.y() == 1 || from.y()-to.y() == -1))
           isOK=true;
    }

    break;
    case exiang:
    case exiangg:
    {
      if ( ((to.x() - from.x()== -2 || to.x() - from.x() ==2)
           &&(to.y() - from.y()== -2 || to.y() - from.y() ==2))
           ||
           ((from.x() - to.x()== -2 || from.x() - to.x() ==2)
            &&(from.y() - to.y()== -2 || from.y() - to.y() ==2))
          )
          {
            if((from.x() == 5 && to.x()==3)||(from.x()==4 && to.x()==6)) //not over river
             isOK = false;
            else if (from.x()>to.x()&&from.y()>to.y()) //up-left
            {
                if(recoLocTable[from.x()-1][from.y()-1] == 1)
                  isOK=false;
                else
                  isOK=true;
            }
            else if (from.x()>to.x()&&from.y()<to.y()) //up-right
            {
                if(recoLocTable[from.x()-1][from.y()+1] == 1)
                  isOK=false;
                else
                  isOK=true;
            }
            else if (from.x()<to.x()&&from.y()>to.y()) //down-left
            {
                if(recoLocTable[from.x()+1][from.y()-1] == 1)
                  isOK=false;
                else
                  isOK=true;
            }
            else if (from.x()<to.x()&&from.y()<to.y()) //down-right
            {
                if(recoLocTable[from.x()+1][from.y()+1] == 1)
                  isOK=false;
                else
                  isOK=true;
            }
            else
             isOK = true;
          }
    }

    break;

    case ezu:
    {
      //!over river
      if( to.y()== from.y() && to.x()- from.x() == 1 && to.x()<5) //
        isOK = true;
      //over river
      else if (
             (from.x()==to.x()||from.y()==to.y())
             && to.x()>=5
             && (
                 ( from.x()-to.x() == -1 && from.x()-to.x() != 1 )
                 ||( from.y()-to.y() == 1 || from.y()-to.y() == -1)
                 )
             )
        isOK = true;
      else{}
    }
    break;

    default:
    {}
   } //end 'switch'
   return isOK;
 }

void CheeseBoard::moveCheese(Cheese* cheese, Masks* mask)
{
    QPointF oldPos;
    QPointF newPos;
    QPoint oldLocation;
    QPoint newLocation;
    int index = 0;

     //properties of cheese
     newLocation = mask->toGetLocation();
     oldLocation = cheese->toGetLocation();
     index = newLocation.rx()*(row-1) + newLocation.ry();
     newPos = points.at(index);
     oldPos = cheese->pos(); //old pos of cheese

     //remove a cheese
     cheese->setLocation(newLocation);
     cheese->setPos(newPos); //new pos of cheese
     cheese->setSelect(false);

     //remove a mask
     mask->setLocation(oldLocation);
     mask->setPos(oldPos);
     mask->setOpacity(0.1);

     //reset & init reco.loc.table
     recoLocTable[oldLocation.rx()][oldLocation.ry()] = 0;
     recoLocTable[newLocation.rx()][newLocation.ry()] = 1;
     reset();
}

 void CheeseBoard::eatCheese(Cheese* from,Cheese* to)
 {
     QPointF oldPos;
     QPointF newPos;
     QPoint oldLocation;
     QPoint newLocation;
     CheesesType type;
     int index = 0;

      //proporties of cheese
      type = to->toGetCheesesType();
      newLocation = to->toGetLocation();
      oldLocation = from->toGetLocation();
      index = newLocation.rx()*(row-1) + newLocation.ry();
      newPos = points.at(index);
      oldPos = from->pos(); //old pos of cheese

      //destroy ate cheese
      removeItem(to);
      delete to;

      //removed cheese
      from->setLocation(newLocation);
      from->setPos(newPos); //new pos of cheese
      from->setSelect(false);

      //added a mask in old location
      Masks* mask = new Masks(emask,from->toGetRadius(),oldLocation);
      mask->setPos(oldPos);
      mask->setOpacity(0.1);
      addItem(mask);

      //reset & init reco.loc.table
      recoLocTable[oldLocation.rx()][oldLocation.ry()] = 0;
      recoLocTable[newLocation.rx()][newLocation.ry()] = 1;
      reset();

      //game over?
      if (type == eshuai || type == ejiang)
        toGetParent()->showWinMsg(type);
 }

void CheeseBoard::mousePressEvent ( QGraphicsSceneMouseEvent * mouseEvent )
{
   QTransform transform;
   QGraphicsItem* graphicsItem = itemAt(mouseEvent->scenePos(),transform);
   item = qgraphicsitem_cast<Items *>( graphicsItem );
   if(item!=NULL)
   {
     if (item->toGetCheesesType() == emask)
     {
       qDebug()<<"clicked a mask@"<<item->toGetLocation();
       mask = qgraphicsitem_cast<Masks *>( item );
       if(cheese!=NULL&&cheese->isSelected())
       {
         if( isLegalMove(*cheese,*mask))
             moveCheese(cheese,mask);
       }//end if
     }//end 'emask'
     else
     {
         Cheese* newCheese = NULL;
         if(cheese == NULL)
         {
           cheese= qgraphicsitem_cast<Cheese *>( item );
         }
         else
         {
           // previous cheese->toGetLocation() // previous
           newCheese= qgraphicsitem_cast<Cheese *>( item );
         }
       if( newCheese!=NULL )
         {
           // newCheese->toGetLocation() //new
           bool isLegal = isLegalEat(*cheese,*newCheese);
           if( isLegal )
           {
             qDebug()<<"eating";
             eatCheese(cheese,newCheese);
           }
           else
            qDebug()<<"illegal eating";
           cheese = newCheese;
         }
       cheese->setSelect(true);
     }//end 'cheese'
   } //end 'if(item!=NULL)'
   else
   {
     qDebug()<<"You clicked on empty pos";
   }
}

void CheeseBoard::mouseMoveEvent ( QGraphicsSceneMouseEvent * mouseEvent )
{
  QGraphicsScene::mouseMoveEvent(mouseEvent);
}

void CheeseBoard::mouseReleaseEvent ( QGraphicsSceneMouseEvent * mouseEvent )
{

  QGraphicsScene::mouseReleaseEvent(mouseEvent);
}
